<?php

declare(strict_types=1);

namespace Zms\Validate\Rule;

use Zms\Unit\Is;

/**
 * 日期格式验证类
 * 用于验证日期时间格式是否正确，并支持将日期时间转换为指定格式或时间戳。
 */
class DateFormatValidate extends RuleAbstract
{
    /**
     * 设置错误信息
     * 默认错误信息模板，用于在验证失败时返回。
     * @var string
     */
    protected $_error = '{label}不是有效时间';

    /**
     * 时间格式验证
     * 用于指定验证通过后输出的日期时间格式。
     * 如果为空，则直接返回原始值。
     * @var ?string
     */
    protected $_output = null;

    /**
     * 是否输出时间戳
     * 如果设置为 true，则验证通过后返回时间戳。
     * @var bool
     */
    protected $_timestamp = false;

    /**
     * 时间补全规则
     * 用于将不完整的时间补全为完整的时间格式。
     * @var string
     */
    protected $_completion = '';

    /**
     * 设置输出日期时间格式
     * @param string $output 日期时间格式，如 'Y-m-d H:i:s'
     * @return $this
     */
    public function setOutput(string $output)
    {
        $this->_output = $output;
        return $this;
    }

    /**
     * 设置是否输出时间戳
     * @param bool $timestamp 是否输出时间戳
     * @return $this
     */
    public function setTimestamp(bool $timestamp)
    {
        $this->_timestamp = $timestamp;
        return $this;
    }

    /**
     * 设置时间补全规则
     * @param string $completion 时间补全格式，如 'Y-m-d'
     * @return $this
     */
    public function setCompletion(string $completion)
    {
        $this->_completion = $completion;
        return $this;
    }

    /**
     * 验证日期时间
     * 验证输入值是否为有效日期时间，并根据配置返回相应格式或时间戳。
     * @param mixed $value 验证值
     * @param string $label 验证名
     * @return bool 验证结果
     */
    public function validate($value, string $label = ''): bool
    {
        if (is_string($value)) {
            // 如果值为空且不允许跳过验证，则直接返回 true
            if (Is::empty($value) && $this->_noSkipping === true) {
                $this->_value = '';
                return true;
            }

            // 验证时间格式是否正确
            $time = strtotime($value);
            if ($time === false) {
                return $this->addError($this->_error, $label);
            }

            // 如果设置了时间补全规则，则补全时间
            if ($this->_completion) {
                $current = date($this->_completion, time());
                $val_len = strlen($value);
                $current_len = strlen($current);
                if ($current_len > $val_len) {
                    $value = substr_replace($current, $value, 0, $val_len);
                }
            }

            // 如果设置为输出时间戳，则直接返回时间戳
            if ($this->_timestamp === true) {
                $this->_value = $time;
                return true;
            }

            // 如果设置了输出格式，则格式化日期时间
            $this->_value = $this->_output ? date($this->_output, $time) : $value;
            return true;
        }

        // 如果输入值不是字符串，则验证失败
        return $this->addError($this->_error, $label);
    }
}
